//    Copyright (C) Kherty.  All rights reserved.
using System;

namespace OpenLS.Spreadsheet.Parsing
{
    sealed class NumericCreator : TokenCreator
    {
        public override char[] FirstChars()
        {
            return CharTypeManager.NumericsDot();
        }
        int Len;
        public override Token Match(Lexer l)
        {
            Len = 0;
            bool hadDot = false;
            bool hadAfterDot = false;
            bool hadL = false;
            bool hadU = false;
            bool hadE = false;
            bool acceptE = false;
            bool tryHexa = false;
            bool eAfterDot = false;
            try
            {
                if ((l.CurrentCharAt(Len) == '0' &&
                    (l.CurrentCharAt(Len + 1) == 'X' || l.CurrentCharAt(Len + 1) == 'x'))
                    && CharTypeManager.IsHexa(l.CurrentCharAt(Len + 2)))
                {
                    tryHexa = true;
                }
            }
            catch (Exception)
            { }
            if (tryHexa) // TODO: Check  that hexa stuff
            {
                Len = Len + 2;
                while (true)
                {
                    char c = l.CurrentCharAt(Len);
                    if (!CharTypeManager.IsHexa(c))
                    {
                        if (c == 'l' || c == 'L')
                        {
                            Len++;
                            hadL = true;
                            try
                            {
                                c = l.CurrentCharAt(Len);
                                if (c == 'u' || c == 'U')
                                {
                                    Len++;
                                    hadU = true;
                                }
                            }
                            catch { }
                            if (hadU)
                                return new Numeric(l.Substring(l.Position + 2, Len - 2 - 2), l.Substring(l.Position, Len), typeof(ulong), true);
                            return new Numeric(l.Substring(l.Position + 2, Len - 2 - 1), l.Substring(l.Position, Len), typeof(long), true);
                        }
                        if (c == 'u' || c == 'U')
                        {
                            Len++;
                            hadU = true;
                            try
                            {
                                c = l.CurrentCharAt(Len);
                                if (c == 'l' || c == 'L')
                                {
                                    Len++;
                                    hadL = true;
                                }
                            }
                            catch { }
                            if (hadL)
                                return new Numeric(l.Substring(l.Position + 2, Len - 2 - 2), l.Substring(l.Position, Len), typeof(ulong), true);
                            return new Numeric(l.Substring(l.Position + 2, Len - 2 - 1), l.Substring(l.Position, Len), typeof(uint), true);
                        }
                        string s = l.Substring(l.Position + 2, Len - 2);
                        string s2 = l.Substring(l.Position, Len);
                        return new Numeric(s, s2, true);
                    }
                    Len++;
                }
            }
            else
            {
                while (true)
                {
                    char c = l.CurrentCharAt(Len);
                    if (!hadDot && c == '.')
                    {
                        hadDot = true;
                    }
                    else
                    {
                        if (hadDot)
                        {
                            if (CharTypeManager.IsNumeric(c))
                                hadAfterDot = true;
                        }
                        if ((c == 'e' || c == 'E') && !hadE && acceptE)
                        {
                            if (l.CurrentCharAt(Len + 1) == '-' || l.CurrentCharAt(Len + 1) == '+')
                                Len++;
                            hadE = true;
                            if (hadDot && !hadAfterDot)
                            {
                                eAfterDot = true;
                            }
                        }
                        else if (!CharTypeManager.IsNumeric(c))
                        {
                            if (Len == 1 && hadDot)
                                return null;
                            if (hadDot && !hadAfterDot && Len > 1)
                            {
                                //Len = Len ;
                                if (eAfterDot)
                                    Len--;
                                return new Numeric(l.Substring(l.Position, Len-1), l.Substring(l.Position, Len));
                            }
                            if (c == 'f' || c == 'F')
                            {
                                Len++;
                                return new Numeric(l.Substring(l.Position, Len - 1), l.Substring(l.Position, Len), typeof(float));
                            }
                            if (c == 'd' || c == 'D')
                            {
                                Len++;
                                return new Numeric(l.Substring(l.Position, Len - 1), l.Substring(l.Position, Len), typeof(double));
                            }
                            if (c == 'm' || c == 'M')
                            {
                                Len++;
                                return new Numeric(l.Substring(l.Position, Len - 1), l.Substring(l.Position, Len), typeof(decimal));
                            }
                            if (c == 'l' || c == 'L')
                            {
                                Len++;
                                hadL = true;
                                try
                                {
                                    c = l.CurrentCharAt(Len);
                                    if (c == 'u' || c == 'U')
                                    {
                                        Len++;
                                        hadU = true;
                                    }
                                }
                                catch { }
                                if (hadU)
                                    return new Numeric(l.Substring(l.Position, Len - 2), l.Substring(l.Position, Len), typeof(ulong));
                                return new Numeric(l.Substring(l.Position, Len - 1), l.Substring(l.Position, Len), typeof(long));
                            }
                            if (c == 'u' || c == 'U')
                            {
                                Len++;
                                hadU = true;
                                try
                                {
                                    c = l.CurrentCharAt(Len);
                                    if (c == 'l' || c == 'L')
                                    {
                                        Len++;
                                        hadL = true;
                                    }
                                }
                                catch { }
                                if (hadL)
                                    return new Numeric(l.Substring(l.Position, Len - 2), l.Substring(l.Position, Len), typeof(ulong));
                                return new Numeric(l.Substring(l.Position, Len - 1), l.Substring(l.Position, Len), typeof(uint));
                            }
                            return new Numeric(l.Substring(l.Position, Len), l.Substring(l.Position, Len));
                        }
                        acceptE = true;
                    }
                    Len++;
                }
            }
        }
        public override int MatchSize()
        {
            return Len;
        }
    }
}